package tsb.trinhnx;

public class Tree<T> {

	private TreeNode<T> root;

	public Tree() {
		root = null;
	}

	public Tree(TreeNode<T> root) {
		this.root = root;
	}

	/**
	 * Insert a node with parent is another one
	 * @param node
	 * @param parent
	 */
	public void addNode(final TreeNode<T> node, final TreeNode<T> parent) {
		// If insert but the null parent, insert this as root
		if (parent == null) {
			root = node;
		} else {
			if (node == null) {
				throw new NullPointerException("Node is null");
			}
			node.setParent(parent);
			TreeNode<T> child = parent.getFirstChild();
			if (child == null) {
				parent.setFirstChild(node);
			} else {
				node.setNextSibling(child);
			}
		}
	}

	/**
	 * Add a value
	 * @param value
	 * @param parent
	 */
	public void addNode(final T value, final TreeNode<T> parent) {
		// If insert but the null parent, insert this as root
		TreeNode<T> node = new TreeNode<T>(value);
		// Call the addNode for new node
		addNode(node, parent);
	}

	/**
	 * Check a node in this tree
	 * @param node 	: node to find
	 * @return		: return true if found, false if not
	 */
	public boolean isExist(final TreeNode<T> node) {
		return !(findNode(node, root) == null);
	}

	/**
	 * Find a node in this tree
	 * @param node 	: node to find
	 * @return		: return this node if exist, else return null
	 */
	public TreeNode<T> findNode(final TreeNode<T> node, final TreeNode<T> root) {
		TreeNode<T> result = null;
		if (root == null) {
			return result;
		} else {
			// We will find until 
			if (root.compare(root.getNodeValue(), node.getNodeValue()) == 0) {
				result = root;
			} else {
				// Travel in all children and its sibling
				findNode(node, root.getFirstChild());
				findNode(node, root.getFirstChild().getNextSibling());
			}
		}
		return result;
	}

}
